﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wormhole.Engine.Communication.Messages
{
	/// <author>Hannes Foulds</author>
	/// <date>04 September 2008</date>
	/// <summary>
	/// This is the base class for all messages.
	/// </summary>
	public abstract class Message
	{
		#region Properties
		
		#region Action
		/// <summary>
		/// The message action.
		/// </summary>
		public Actions Action { get; set; }
		#endregion
		
		#region Game
		/// <summary>
		/// The game object.
		/// </summary>
		public Game Game { get; set; }
		#endregion

		#region To
		/// <summary>
		/// The player or channel to which the message should be sent.
		/// </summary>
		public string To { get; set; }
		#endregion

		#region Player Name
		/// <summary>
		/// The name of the player who made the request.
		/// </summary>
		public string PlayerName { get; set; }
		#endregion

		#region Channel
		/// <summary>
		/// The channel on which the request was made.
		/// </summary>
		public string Channel { get; set; }
		#endregion

		#endregion

		#region Encode String
		/// <summary>
		/// Encode a string to prepare it to be transmitted over the communications channel.
		/// </summary>
		/// <param name="message">The message to encode.</param>
		/// <returns>Returns the encoded string.</returns>
		public string EncodeString(string message)
		{
			string result = "";

			if (!string.IsNullOrEmpty(message))
			{
				result = message;

				// replace special characters
				result = result.Replace("&", "&quote;");
				result = result.Replace("|", "&pipe;");
			}
			// return the encoded string
			return result;
		}
		#endregion

		#region Decode String
		/// <summary>
		/// Decode a string that was received over the communicagtions channel.
		/// </summary>
		/// <param name="message">The received string.</param>
		/// <returns>Returns the decoded string.</returns>
		public string DecodeString(string message)
		{
			string result = message;

			// replace special characters
			result = result.Replace("&pipe;", "|");
			result = result.Replace("&quote;", "&");

			// return the encoded string
			return result;
		}
		#endregion

		#region Parse
		/// <summary>
		/// Parse the string message and returns a message object based on the request action type.
		/// </summary>
		/// <param name="channel">The channel the message is from.</param>
		/// <param name="playerName">The player sending the message.</param>
		/// <param name="message">The message.</param>
		/// <param name="gameList">The list of waiting games.</param>
		/// <returns>Returns a message object of the appropriate type.</returns>
		public static Message Parse(string channel, string playerName, string message, Dictionary<Guid, Game> gameList)
		{
			Message requestMessage = null;

			// determine the action type
			string actionString = message;
			if (actionString.Contains("|"))
				actionString = message.Substring(0, message.IndexOf("|"));

			Actions action = EnumConvertor <Actions>.FromString(actionString);

			// create the appropriate request object
			switch (action)
			{
				case Actions.GameListRequest:
					requestMessage = new GameListMessage(message, action, playerName);
					break;
				case Actions.GameList:
					requestMessage = new GameListMessage(message, action, playerName);
					break;
				case Actions.RandomSeed:
					requestMessage = new RandomSeedMessage(message);
					break;
				case Actions.NewDeck:
					requestMessage = new CardMessage(message, action);
					break;
				case Actions.ContinueDeck:
					requestMessage = new CardMessage(message, action);
					break;
				case Actions.EndDeck:
					requestMessage = new CardMessage(message, action);
					break;
				case Actions.RequestJoin:
					requestMessage = new JoinGameMessage(message, action, gameList);
					break;
				case Actions.AcceptJoin:
					requestMessage = new JoinGameMessage(message, action, gameList);
					break;
				case Actions.RejectJoin:
					requestMessage = new JoinGameMessage(message, action, gameList);
					break;
				case Actions.GameClosed:
					requestMessage = new GameClosedMessage(message, gameList);
					break;
				case Actions.KeepHand:
					requestMessage = new HandMessage(message, action);
					break;
				case Actions.TakeMulligan:
					requestMessage = new HandMessage(message, action);
					break;
				case Actions.CardAction:
					requestMessage = new CardActionMessage(message);
					break;
				case Actions.GameAction:
					requestMessage = new GameActionMessage(message);
					break;
			}

			// set the common properties of the message
			if (requestMessage != null)
			{
				requestMessage.Action = action;
				requestMessage.Channel = channel;
				requestMessage.PlayerName = playerName;
			}

			return requestMessage;
		}
		#endregion

		#region To String
		/// <summary>
		/// Convert the message to a string that can be send via the communications channel.
		/// </summary>
		/// <returns>Returns the string representation of the message.</returns>
		public abstract override string ToString();
		#endregion
	}
}
